import pandas as pd
import numpy as np
#Leitura da base de dados
data = pd.read_csv('/home/notbru/Documents/Luizalabs/desafio.csv')
# Checando informação das variáveis disponÃveis
data.info()
data.head()
# convertendo a data de captura para o formato data
data['capture_date'] = pd.to_datetime(data['capture_date'], format='%Y-%m-%d', errors='coerce')
# substituindo data zerada por missing e convertendo para formato data
data['process_date'] = data['process_date'].replace('0000-00-00', np.nan)
data['process_date'] = pd.to_datetime(data['process_date'], format='%Y-%m-%d')
data['month'] = pd.DatetimeIndex(data['capture_date']).month
data['year'] = pd.DatetimeIndex(data['capture_date']).year
data['month_year'] = data['capture_date'].apply(lambda x: x.strftime('%m-%Y'))
data['month_year'] = pd.to_datetime(data['month_year'], format= '%m-%Y')
data.describe()
print('Número de categorias distintas: ', len(set(data['category'])))
print('Número de itens distintos: ', len(set(data['code'])))
print('Canais distintos: ', len(set(data['source_channel'])))
# criando a variável de vendas totais e preço unitário
data['total_sales'] = data['price']
data['unit_price'] = data['price']/data['quantity']
import seaborn as sns
import matplotlib
import squarify
import missingno as msno
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
%matplotlib inline
#Avaliando se a base contém dados faltantes
#A variável process_date apresentará missing dado o ajuste realizado anteriormente para converter o formato em data
msno.matrix(df=data, figsize=(20, 5), color=(0, 0, 0))
# Base agregada pelo status do pedido - ordenada pela quantidade total
dataorder = data.groupby(['order_status']).sum().sort_values('quantity', ascending=False)
dataorder['order_status'] = dataorder.index
dataorder['Imp_order_status']=dataorder['quantity']/dataorder['quantity'].sum()
f, ax = plt.subplots(figsize=(10, 5))
sns.barplot(x='Imp_order_status', y='order_status', data=dataorder)
ax.set(ylabel="", xlabel="Percentual de pedidos por status")
# Base agregada pelo status do pedido - ordenada pela quantidade total
datachannel = data.groupby(['source_channel']).sum().sort_values('quantity', ascending=False)
datachannel['source_channel'] = datachannel.index
datachannel['Imp_source_channel']=datachannel['quantity']/dataorder['quantity'].sum()
print('O principal canal responde por ', "{:.1%}".format(datachannel['Imp_source_channel'].head(1).sum()), 'das vendas em unidades')
f, ax = plt.subplots(figsize=(10, 5))
sns.barplot(x='Imp_source_channel', y='source_channel', data=datachannel)
ax.set(ylabel="", xlabel="Percentual de pedidos por canal")
# Base agregada pelo item - ordenada pela quantidade total
datacat = data.groupby(['category']).sum().sort_values('quantity', ascending=False)
datacat['category'] = datacat.index
datacat['Imp_cat']=datacat['quantity']/datacat['quantity'].sum()
print('Top 3 categorias respondem por ', "{:.1%}".format(datacat['Imp_cat'].head(3).sum()), 'das vendas em unidades')
f, ax = plt.subplots(figsize=(10, 5))
sns.barplot(x='Imp_cat', y='category', data=datacat)
ax.set(ylabel="", xlabel="Importancia das Categorias")
datacode = data[['category','code','quantity']].groupby(['category','code']).sum()
datacode.groupby('category').agg(['sum','count','mean'])
datacode.sort_values('quantity', ascending=False).head(10)
# Base agregada pelo item - ordenada pela quantidade total
datacode = data.groupby(['code']).sum().sort_values('quantity', ascending=False)
datacode['code'] = datacode.index
datacode['Imp_code']=datacode['quantity']/datacode['quantity'].sum()
datacode10 = datacode.head(10)
print('Os top 10 itens respondem por ', "{:.1%}".format(datacode10['Imp_code'].sum()))
f, ax = plt.subplots(figsize=(10, 5))
sns.barplot(x='Imp_code', y='code', data=datacode10)
ax.set(ylabel="", xlabel="Importancia dos top 10 itens")
datats = pd.crosstab(data.capture_date, data.category, data.quantity, aggfunc=sum)
for i in datats.columns:
plt.figure()
datats[i].plot(figsize=(12, 6))
plt.ylabel(i)
# Importando os pacotes a serem utilizados
from sklearn.cluster import KMeans
from sklearn import metrics
from scipy.spatial.distance import cdist
# Transformando a base de dados para rodar a análise de cluster
# Neste caso usaremos a data como um feature e os itens como os exemplos
# Foi feita a substituição de missing por '-1'
dataclus = pd.crosstab(data.code, data.capture_date, data.quantity, aggfunc = sum).replace(np.NaN,0)
dataclus.head()
# Definindo o melhor número de clusters
import random
random.seed(7)
distancia = []
K = range(1,130)
for k in K:
km = KMeans(n_clusters=k).fit(dataclus)
km.fit(dataclus)
distancia.append(sum(np.min(cdist(dataclus, km.cluster_centers_, 'euclidean'), axis=1)) / dataclus.shape[0])
# Plotando o gráfico de cotovelo
plt.figure(figsize=(12,5))
plt.plot(K, distancia)
plt.xlabel('Número de grupos')
plt.ylabel('Distância')
plt.title('Gŕafico de cotovelo para diferentes segmentações de grupos')
plt.xticks(np.arange(0,140, 10))
plt.show()
plt.figure(figsize=(12,5))
plt.plot([j-i for i, j in zip(distancia[:-1], distancia[1:])])
plt.xticks(np.arange(0, 131, 5))
plt.show()
# Considerando que à partir de 11 clusters a distância média dentro dos clusters aumenta
# e depois volta a decrescer mais lentamente
kmeans = KMeans(n_clusters=11)
clus_data = pd.DataFrame.as_matrix(dataclus)
kmeans.fit(clus_data)
dataclus.reset_index(inplace=True)
dataclus['cluster'] = kmeans.labels_
dataclus_f = pd.merge(data, dataclus[['code','cluster']], how='left', on=['code'])
dataclus_ts = dataclus_f.groupby(['category', 'code', 'capture_date', 'cluster']).sum()
dataclus_ts.reset_index(inplace=True)
f, ax = plt.subplots(figsize=(12, 6))
ax = sns.pointplot(x='capture_date', y='quantity', hue='cluster', data=dataclus_ts, ci=None)
datagroup=dataclus_f[['code','quantity','cluster']].groupby(['cluster','code']).sum()
datagroup.groupby('cluster').agg(['sum','count','mean'])
pd.crosstab(dataclus_f.category, dataclus_f.cluster, dataclus_f.quantity, aggfunc = sum)
for i in np.unique(dataclus_ts['cluster']):
f, ax = plt.subplots(figsize=(12, 6))
ax = sns.pointplot(x='capture_date', y='quantity', hue='category', data=dataclus_ts[dataclus_ts['cluster']==i], ci=None)
plt.title('Cluster '+str(i))
fig.autofmt_xdate()
myFmt = matplotlib.dates.DateFormatter('%Y-%m-%d')
ax.xaxis.set_major_formatter(myFmt)
ax.xaxis.set_major_locator(matplotlib.dates.MonthLocator(interval=1))
data = data[(data['order_status'] == 'entrega total') | (data['order_status'] =='em rota de entrega') | (data['order_status'] =='entrega parcial')]
data = data[(data['capture_date'] != '2017-06-01')]
dataclus_f = pd.merge(data, dataclus[['code','cluster']], how='left', on=['code'])
dataclus_ts = dataclus_f.groupby(['category', 'code', 'capture_date', 'cluster']).sum()
dataclus_ts.reset_index(inplace=True)
dataprophet = pd.crosstab(dataclus_ts.capture_date, dataclus_ts.cluster, dataclus_ts.quantity, aggfunc=sum)
dataprophet.tail()
fig, ax = plt.subplots(figsize=(20,7))
ax.plot(dataprophet)
fig.autofmt_xdate()
myFmt = matplotlib.dates.DateFormatter('%Y-%m-%d')
ax.xaxis.set_major_formatter(myFmt)
ax.xaxis.set_major_locator(matplotlib.dates.DayLocator(interval=7))
plt.show()
# Checando as datas "Outliers" de cada cluster
dataprophet[10].sort_values(ascending=False).head(10)
from fbprophet import Prophet
from fbprophet.diagnostics import cross_validation
bf = pd.DataFrame({
'holiday': 'blackfriday',
'ds': pd.to_datetime(['2016-11-25','2016-11-24']),
'lower_window': 0,
'upper_window': 1,
})
ny = pd.DataFrame({
'holiday': 'newyear',
'ds': pd.to_datetime(['2017-01-06','2017-01-07']),
'lower_window': 0,
'upper_window': 1,
})
events = pd.concat((bf, ny))
result={}
dataprophet_cv={}
error={}
for i in dataprophet.columns:
x=pd.DataFrame(dataprophet[i])
x.reset_index(inplace=True)
x.columns = ['ds','y']
x['y']=np.log(x['y'])
m=Prophet(weekly_seasonality=True, yearly_seasonality=True, daily_seasonality=False, holidays=events, interval_width=0.95)
m.fit(x)
future=m.make_future_dataframe(periods=91)
forecast = m.predict(future)
m.plot(forecast)
m.plot_components(forecast)
result[i]=pd.merge(forecast[['ds', 'yhat_lower', 'yhat_upper','yhat']],x,how='left', on=['ds'])
#Cross validation
dataprophet_cv[i]=cross_validation(m, horizon = '31 days')
for i in range(0,len(result)):
#convertendo os dados de volta para a unidade original
result[i]['y']=np.exp(result[i]['y'])
result[i]['yhat']=np.exp(result[i]['yhat'])
result[i]['yhat_lower']=np.exp(result[i]['yhat_lower'])
result[i]['yhat_upper']=np.exp(result[i]['yhat_upper'])
result_f={}
for i in range(0,len(result)):
#Agrupando por mês
result[i]['month_year']=result[i]['ds'].apply(lambda x: x.strftime('%m-%Y'))
result[i]['month_year']=pd.to_datetime(result[i]['month_year'], format= '%m-%Y')
result_f[i]=result[i].groupby('month_year').sum()
result_f[i].replace(np.nan,0)
for i in range(0,len(result)):
#plot
plt.figure(figsize=(20,7))
result_f[i].plot()
plt.title('cluster '+str(i))
plt.show()
from sklearn.metrics import mean_absolute_error
def mean_absolute_percentage_error(y_true, y_pred):
y_true, y_pred = np.array(y_true), np.array(y_pred)
return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
MAE={}
MAPE={}
for i in range(0,len(dataprophet_cv)):
dataprophet_cv[i]['y']=np.exp(dataprophet_cv[i]['y'])
dataprophet_cv[i]['yhat']=np.exp(dataprophet_cv[i]['yhat'])
MAE[i]=mean_absolute_error(dataprophet_cv[i]['y'],dataprophet_cv[i]['yhat'])
MAPE[i]=mean_absolute_percentage_error(dataprophet_cv[i]['y'],dataprophet_cv[i]['yhat'])
MAPE